package com.boarsoft.boar.code.analysis.service.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Component;

import com.boarsoft.boar.code.analysis.service.InterfaceAnalysis;
import com.boarsoft.boar.code.entity.MethodInfo;
import com.boarsoft.boar.code.entity.MethodParamInfo;
import com.boarsoft.boar.code.svc.biz.MethodInfoBiz;
import com.boarsoft.boar.code.svc.biz.MethodParamInfoBiz;
import com.boarsoft.boar.soagov.entity.FaceInfo;
import com.boarsoft.boar.soagov.svc.FaceInfoService;
import com.github.javaparser.StaticJavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.ImportDeclaration;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.PackageDeclaration;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.body.Parameter;

@Component("interfaceAnalysis")
public class InterfaceAnalysisImpl implements InterfaceAnalysis {
	private static final Logger log = LoggerFactory.getLogger(InterfaceAnalysisImpl.class);
	private static final String REGEX = "\\\n";
	@Autowired
	private MethodInfoBiz methodInfoBiz;

	@Autowired
	private MethodParamInfoBiz methodParamInfoBiz;
	@Resource
	private FaceInfoService faceInfoService;

	@Override
	public void execute(String info) {
		try {
			CompilationUnit cu = StaticJavaParser.parse(info);
			List<PackageDeclaration> pds = cu.findAll(PackageDeclaration.class);
			List<ImportDeclaration> ids = cu.findAll(ImportDeclaration.class);
			List<ClassOrInterfaceDeclaration> cds = cu.findAll(ClassOrInterfaceDeclaration.class);
			List<MethodDeclaration> mds = cu.findAll(MethodDeclaration.class);
			String faceId = this.saveFace(cds,pds);
			if (!Objects.isNull(faceId)) {
				this.saveMethod(pds, mds, ids,cds,faceId);
			}
		} catch (Exception e) {
			log.error("转换错误,..");
		}
	}

	/**
	 * 保存接口信息
	 */
	private String saveFace(List<ClassOrInterfaceDeclaration> cds,List<PackageDeclaration> pds) {
		String faceId = null;
		for (int i = 0; i < cds.size(); i++) {
			ClassOrInterfaceDeclaration classOrInterfaceDeclaration = cds.get(i);
			FaceInfo faceInfo = new FaceInfo();
			faceInfo.setFace(this.getFaceName(pds,cds));
			faceInfo.setMemo(classOrInterfaceDeclaration.getComment().toString());
			faceInfo.setStatus(Short.parseShort("1"));
			faceInfo.setCode(classOrInterfaceDeclaration.getName().toString());
			faceInfo.setName(classOrInterfaceDeclaration.getName().toString());
			faceInfo.setVer("");
			faceInfo.setParams(null);
			faceId = faceInfoService.save(faceInfo);
		}
		return faceId;
	}

	/**
	 * 保存方法信息
	 */
	private void saveMethod(List<PackageDeclaration> pds, List<MethodDeclaration> mds, List<ImportDeclaration> ids, List<ClassOrInterfaceDeclaration> cds,String faceId) {
		List<MethodInfo> methodInfos = new ArrayList<>();
		mds.forEach(methodDeclaration -> {
			String method = methodDeclaration.getTokenRange().toString();
			if (method.contains("[") && method.contains("]")) {
				method = method.substring(method.indexOf("[") + 1, method.indexOf("]") - 1);
			}
			if (method.contains("@")) {
				String[] methods = method.split(REGEX);
				for (String s : methods) {
					if (s.startsWith("@")) {
						continue;
					}
					method = s;
				}
			}
			method = method.trim();
			MethodInfo methodInfo = new MethodInfo();
			methodInfo.setCode(method);
			methodInfo.setMemo(methodDeclaration.getComment().toString());
			methodInfo.setFace(this.getFaceName(pds,cds));
			methodInfo.setStatus(1);
			methodInfo.setFaceId(faceId);
			methodInfo.setRtnType(this.typeConvert(methodDeclaration.getTypeAsString(),pds,ids));
			String id = null;
			try {
				id = methodInfoBiz.save(methodInfo, this.getFaceName(pds,cds));
			} catch (DataIntegrityViolationException e) {
				id = methodInfoBiz.selectMethodId(methodInfo);
			}
			methodInfos.add(methodInfo);
			if (!Objects.isNull(id)) {
				this.saveMethodParam(id, methodDeclaration,pds,ids);
			}
		});
		this.deleteInvalidInfo(methodInfos, faceId);
	}

	/**
	 * 删除无效数据
	 * 
	 * @param methodInfos
	 *            method信息列表
	 * @param faceId
	 *            接口id
	 */
	private void deleteInvalidInfo(List<MethodInfo> methodInfos, String faceId) {
		List<MethodInfo> methodInfoList = methodInfoBiz.findMethodInfoByFaceId(faceId);
		for (MethodInfo methodInfo : methodInfoList) {
			boolean flag = true;
			for (MethodInfo methodInfo1 : methodInfos) {
				if (methodInfo.getCode().equals(methodInfo1.getCode())) {
					flag = false;
					break;
				}
			}
			if (flag) {
				methodInfoBiz.deleteById(methodInfo.getId());
			}
		}
	}

	/**
	 * 保存参数信息
	 * 
	 * @param id
	 *            id
	 * @param methodDeclaration
	 *            方法对象
	 */
	private void saveMethodParam(String id, MethodDeclaration methodDeclaration,List<PackageDeclaration> pds,List<ImportDeclaration> ids) {
		NodeList<Parameter> parameters = methodDeclaration.getParameters();
		for (int i = 0; i < parameters.size(); i++) {
			Parameter parameter = parameters.get(i);
			String type = this.typeConvert(parameter.getType().toString(),pds,ids);
			MethodParamInfo methodParamInfo = new MethodParamInfo();
			methodParamInfo.setMethodId(id);
			methodParamInfo.setName(parameter.getName().toString());
			methodParamInfo.setType(type);
			methodParamInfo.setIndex(i);
			try {
				methodParamInfoBiz.save(methodParamInfo);
			} catch (DataIntegrityViolationException e) {
			}
		}

	}

	/**
	 * 转换类型
	 * 
	 * @param type
	 *            类型
	 * @return 实际类型
	 */
	public String typeConvert(String type,List<PackageDeclaration> pds,List<ImportDeclaration> ids) {
		switch (type) {
		case "String": {
			return "java.lang.String";
		}
		case "int": {
			return "int";
		}
		case "long": {
			return "long";
		}
		case "short": {
			return "short";
		}
		case "boolean": {
			return "boolean";
		}
		case "double": {
			return "double";
		}
		case "float": {
			return "float";
		}
		case "byte": {
			return "byte";
		}
		case "char": {
			return "char";
		}
		case "void": {
			return "void";
		}
		case "Void": {
			return "java.lang.Void";
		}
		case "Long": {
			return "java.lang.Long";
		}
		case "Boolean": {
			return "java.lang.Boolean";
		}
		case "Byte": {
			return "java.lang.Byte";
		}
		case "Character": {
			return "java.lang.Character";
		}
		case "Double": {
			return "java.lang.Double";
		}
		case "Float": {
			return "java.lang.Float";
		}
		case "Integer": {
			return "java.lang.Integer";
		}
		case "Short": {
			return "java.lang.Short";
		}
		case "Object": {
			return "java.lang.Object";
		}
		default: {
			if (type.contains("[")) {
				return typeConvert(type.substring(0, type.indexOf("[")),pds,ids).concat(type.substring(type.indexOf("[")));
			} else if (type.contains("(")) {
				return typeConvert(type.substring(0, type.indexOf("(")),pds,ids).concat(type.substring(type.indexOf("(")));
			} else if (type.contains("<")) {
				return typeConvert(type.substring(0, type.indexOf("<")),pds,ids).concat(type.substring(type.indexOf("<")));
			} else if (type.contains("{")) {
				return typeConvert(type.substring(0, type.indexOf("{")),pds,ids).concat(type.substring(type.indexOf("{")));
			}
			return getString(type, pds, ids);
		}
		}
	}

	static String getString(String type, List<PackageDeclaration> pds, List<ImportDeclaration> ids) {
		for (ImportDeclaration importDeclaration : ids) {
			String importName = importDeclaration.getName().toString();
			if (importName.endsWith(type)) {
				type = importName;
				return type;
			}
		}
		return pds.get(0).getName().toString().concat(".").concat(type);
	}

	public String getFaceName(List<PackageDeclaration> pds,List<ClassOrInterfaceDeclaration> cds) {
		String faceName = pds.get(0).getName().toString().concat(".").concat(cds.get(0).getName().toString());
		if (faceName.endsWith(";")) {
			faceName = faceName.substring(0, faceName.length() - 1);
		}
		return faceName;
	}
}